package rad.framework.jpa;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.hibernate.EntityMode;
import org.hibernate.FlushMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.engine.EntityEntry;
import org.jboss.ejb3.entity.InjectedEntityManagerFactory;
import org.jboss.seam.persistence.HibernateSessionProxy;

/**
 * @author Chunyun Zhao
 */
public class HibernateUtil {

	public static Session getDeletegate(EntityManager em) {
		Object delegate = em.getDelegate();
		if (delegate instanceof Session) {
			return (Session) delegate;
		} else {
			return getDeletegate((EntityManager) delegate);
		}
	}

	public static boolean isFlushModeManual(EntityManager em) {
		Session delegate = HibernateUtil.getDeletegate(em);
		FlushMode mode = delegate.getFlushMode();
		return FlushMode.isManualFlushMode(mode);
	}
	
	public static SessionFactory getSessionFactory(EntityManagerFactory emf) {
		if (emf instanceof InjectedEntityManagerFactory) {
			emf = ((InjectedEntityManagerFactory)emf).getDelegate();
		}
		return ((HibernateEntityManagerFactory) emf).getSessionFactory();
	}

	public static Session getSession(EntityManager em) {
		return getDeletegate(em);
	}

	public static boolean isExistsInDatabase(EntityManager em, Object entity) {
		Session session = (Session) getSession(em);
		if (session instanceof HibernateSessionProxy) {
			HibernateSessionProxy proxy = (HibernateSessionProxy) session;
			EntityEntry entry = proxy.getPersistenceContext().getEntry(entity);
			if (entry != null) {
				return entry.isExistsInDatabase();
			}
		}
		return false;
	}

	/**
	 * http://www.hibernate.org/hib_docs/reference/en/html/xml.html
	 */
	public static Document getXml(EntityManager em, Class clazz, Object id) {
		Document document = DocumentHelper.createDocument();
		Element export = document.addElement("export");
		Element element = getXml(getDomSession(getSession(em)), clazz,
				(Serializable) id);
		export.add(element);
		return document;
	}

	public static Document getXml(EntityManager em, String eql,
			Map<String, Object> parameters) {
		Session session = getDomSession(getSession(em));
		Query qry = session.createQuery(eql);
		for (Iterator i = parameters.keySet().iterator(); i.hasNext();) {
			String key = (String) i.next();
			if (parameters.get(key) != null) {
				qry.setParameter(key, parameters.get(key));
			}
		}
		Document document = DocumentHelper.createDocument();
		Element export = document.addElement("export");
		List<Element> list = qry.list();
		for (Element element : list) {
			export.add(element);
		}
		return document;
	}

	public static Session getDomSession(Session session) {
		return session.getSession(EntityMode.DOM4J);
	}

	public static Element getXml(Session session, Class clazz, Serializable id) {
		Session dsession = getDomSession(session);
		return (Element) dsession.get(clazz, id);
	}

	public static void saveXmlString(Session session, String xml) {
		try {
			Session dsession = getDomSession(session);
			SAXReader reader = new SAXReader();
			Document doc = reader.read(xml);
			Element root = doc.getRootElement();
			dsession.saveOrUpdate(root);
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}

}
